package cn.virens.common.exception;

import cn.virens.common.fun.ExCallback;
import cn.virens.common.fun.ExConsumer;
import cn.virens.common.fun.ExFunction;
import cn.virens.common.fun.ExSupplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

public class ExceptionUtil {
    private static final Logger logger = LoggerFactory.getLogger(ExceptionUtil.class);

    /**
     * 根据异常获取对应的异常参数
     *
     * @param e 异常
     * @return Exception's code
     */
    public static final String c(Throwable e) {
        return getCode(e);
    }

    /**
     * 获取异常提示内容
     *
     * @param e 异常
     * @return Exception's message
     */
    public static final String m(Throwable e) {
        return getMessage(e);
    }

    /**
     * 消费异常抛出
     *
     * @param callback ExCallback
     */
    public static void e0(ExCallback callback) {
        try {
            callback.accept();
        } catch (Throwable cause) {
            throw APIException.warp(cause);
        }
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      返回类型
     * @param supplier ExSupplier
     * @return T
     */
    public static <T> T e1(ExSupplier<T> supplier) {
        try {
            return supplier.get();
        } catch (Throwable cause) {
            throw APIException.warp(cause);
        }
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      参数类型
     * @param obj      调用参数
     * @param consumer ExConsumer
     */
    public static <T> void e2(T obj, ExConsumer<T> consumer) {
        try {
            consumer.accept(obj);
        } catch (Throwable cause) {
            throw APIException.warp(cause);
        }
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      参数类型
     * @param <R>      返回类型
     * @param obj      调用参数
     * @param function ExConsumer
     * @return R
     */
    public static <T, R> R e3(T obj, ExFunction<T, R> function) {
        try {
            return function.apply(obj);
        } catch (Throwable cause) {
            throw APIException.warp(cause);
        }
    }

    /**
     * 消费异常抛出
     *
     * @param callback ExCallback
     */
    public static void safe0(ExCallback callback) {
        safe0(logger, Objects.requireNonNull(callback));
    }

    /**
     * 消费异常抛出
     *
     * @param logger   日志组件
     * @param callback ExCallback
     */
    public static void safe0(Logger logger, ExCallback callback) {
        try {
            callback.accept();
        } catch (Throwable e) {
            log(logger, e);
        }
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      返回类型
     * @param supplier ExSupplier
     * @return T
     */
    public static <T> T safe1(ExSupplier<T> supplier) {
        return safe1(logger, Objects.requireNonNull(supplier));
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      返回类型
     * @param logger   日志组件
     * @param supplier ExSupplier
     * @return T
     */
    public static <T> T safe1(Logger logger, ExSupplier<T> supplier) {
        try {
            return supplier.get();
        } catch (Throwable e) {
            log(logger, e);
        }

        return null;
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      参数类型
     * @param obj      调用参数
     * @param consumer ExConsumer
     */
    public static <T> void safe2(T obj, ExConsumer<T> consumer) {
        safe2(logger, obj, Objects.requireNonNull(consumer));
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      参数类型
     * @param logger   日志组件
     * @param obj      调用参数
     * @param consumer ExConsumer
     */
    public static <T> void safe2(Logger logger, T obj, ExConsumer<T> consumer) {
        try {
            consumer.accept(obj);
        } catch (Throwable e) {
            log(logger, e);
        }
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      参数类型
     * @param <R>      返回类型
     * @param obj      调用参数
     * @param function ExConsumer
     * @return R
     */
    public static <T, R> R safe3(T obj, ExFunction<T, R> function) {
        return safe3(logger, obj, Objects.requireNonNull(function));
    }

    /**
     * 消费异常抛出
     *
     * @param <T>      参数类型
     * @param <R>      返回类型
     * @param logger   日志组件
     * @param obj      调用参数
     * @param function ExConsumer
     * @return R
     */
    public static <T, R> R safe3(Logger logger, T obj, ExFunction<T, R> function) {
        try {
            return function.apply(obj);
        } catch (Throwable e) {
            log(logger, e);
        }

        return null;
    }

    /**
     * 打印异常信息到日志
     *
     * @param ex 异常对象
     */
    public static void log(Throwable ex) {
        log(logger, ex);
    }

    /**
     * 打印异常信息到日志
     *
     * @param logger 日志组件
     * @param ex     异常对象
     */
    public static void log(Logger logger, Throwable ex) {
        logger.error(c(ex) + ":" + m(ex), ex);
    }

    /**
     * 根据异常获取对应的异常参数
     *
     * @param e 异常
     * @return Exception's code
     */
    public static final String getCode(Throwable e) {
        if (e instanceof APIExceptionInter) {
            return ((APIExceptionInter) e).getCode();
        } else if (e != null) {
            return e.getClass().getSimpleName();
        } else {
            return "UNKOWN";
        }
    }

    /**
     * 获取异常提示内容
     *
     * @param e 异常
     * @return Exception's message
     */
    public static final String getMessage(Throwable e) {
        if (e != null) {
            return e.getMessage();
        } else {
            return "未知错误";
        }
    }
}
